﻿
namespace WP7Contrib.View.Controls.Helpers
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Media;
    using System.Windows.Shapes;

    /// <summary>
    /// Couple of simple helpers for walking the visual tree
    /// </summary>
    public static class TreeHelpers
    {
        /// <summary>
        /// counter for fill
        /// </summary>
        private static int counter;

        /// <summary>
        /// Gets the ancestors of the element, up to the root
        /// </summary>
        /// <param name="node">The element to start from</param>
        /// <returns>An enumerator of the ancestors</returns>
        public static IEnumerable<FrameworkElement> GetVisualAncestors(this FrameworkElement node)
        {
            FrameworkElement parent = node.GetVisualParent();
            while (parent != null)
            {
                yield return parent;
                parent = parent.GetVisualParent();
            }
        }

        /// <summary>
        /// Gets the visual parent of the element
        /// </summary>
        /// <param name="node">The element to check</param>
        /// <returns>The visual parent</returns>
        public static FrameworkElement GetVisualParent(this FrameworkElement node)
        {
            return VisualTreeHelper.GetParent(node) as FrameworkElement;
        }

        /// <summary>
        /// Dumps this instance.
        /// </summary>
        public static void Dump()
        {
            Debug.WriteLine(
                "{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
                "ID",
                "layer",
                "cached",
                "hasPixels",
                "area",
                "element");

            Dump((FrameworkElement)Application.Current.RootVisual, 0, 0);
        }

        /// <summary>
        /// Doeses the brush have pixels.
        /// </summary>
        /// <param name="b">The b.</param>
        /// <returns></returns>
        private static bool DoesBrushHavePixels(Brush b)
        {
            // assume gradients have pixels
            var scb = b as SolidColorBrush;

            return b != null && (scb == null || scb.Color != Colors.Transparent);
        }

        /// <summary>
        /// Gets the background brush
        /// </summary>
        /// <param name="fe">
        /// The fe.
        /// </param>
        /// <returns>
        /// </returns>
        private static Brush GetBackgroundBrush(FrameworkElement fe)
        {
            var pi = fe.GetType().GetProperty("Background");
            var brush = pi == null ? null : pi.GetGetMethod().Invoke(fe, new object[] { });
            return brush as Brush;
        }

        /// <summary>
        /// Determines whether [is border with border] [the specified fe].
        /// </summary>
        /// <param name="fe">The fe.</param>
        /// <returns>
        /// <c>true</c> if [is border with border] [the specified fe]; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsBorderWithBorder(FrameworkElement fe)
        {
            var b = fe as Border;
            if (b == null)
            {
                return false;
            }

            return DoesBrushHavePixels(b.BorderBrush);
        }

        /// <summary>
        /// Dumps the specified fe.
        /// </summary>
        /// <param name="fe">The fe.</param>
        /// <param name="treeDepth">The tree depth.</param>
        /// <param name="layerDepth">The layer depth.</param>
        private static void Dump(FrameworkElement fe, int treeDepth, int layerDepth)
        {
            if (fe.Visibility == Visibility.Collapsed)
            {
                return;
            }

            double area = 0;

            var r = LayoutInformation.GetLayoutSlot(fe);
            var xform = fe.TransformToVisual(null);
            var p = xform.Transform(new Point(0, 0));
            var bounds = xform.TransformBounds(r);
            var screen = new Rect(0, 0, 480, 800);
            screen.Intersect(bounds);

            if (!screen.IsEmpty)
            {
                area = screen.Width * screen.Height;
            }
            else
            {
                area = -1;
            }

            // if (area != -1)
            // {
            var name = fe.Name ?? string.Empty;

            var hasPixels = !(fe is Control) && DoesBrushHavePixels(GetBackgroundBrush(fe));

            hasPixels |= IsBorderWithBorder(fe);
            hasPixels |= (fe is Shape) || (fe is TextBlock) || (fe is TextBox);

            if (hasPixels)
            {
                ++layerDepth;
            }
            else
            {
                area = 0;
            }

            var hasCache = fe.CacheMode != null;

            Debug.WriteLine(
                "{0}\t{1}\t{2}\t{3}\t{4}\t\"{5}\"",
                counter,
                layerDepth,
                hasCache ? "Cached" : string.Empty,
                hasPixels,
                area,
                new string(' ', treeDepth * 2) + fe + " (" + name + ")");

            // }
            ++counter;

            var count = VisualTreeHelper.GetChildrenCount(fe);
            for (var index = 0; index < count; ++index)
            {
                Dump((FrameworkElement)VisualTreeHelper.GetChild(fe, index), treeDepth + 1, layerDepth);
            }
        }
    }
}